/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package main.game;

import java.util.ArrayList;
import java.util.Map;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

enum PrefGameState {
    
    GS_WAIT_FOR_ALL_READY, GS_PLAYING, GS_GAME_FINISHED
};

/**
 *
 * @author vova
 */
@ManagedBean
@ApplicationScoped
public class GamesManager {
    
    public GamesManager() {
    }

    /**
    Начинает новую игру
    @param uids Список всех игроков, учавствующих в данной игре
    @param gid Идентификатор для новой игры
    @param conventions Структура содержащая привила и договоренности для данной игры
    @throws GameControllerException не удалось создать новую игру
     */
    public void StartGame(ArrayList<Integer> uids, int gid, GameConventions conventions) throws GameControllerException {
        // если ли уже игра с таким gid?
        if (gameList.get(gid) != null) {
            throw new GameControllerException("Игра с таким ID уже существует");
        }
        GameEngine ge = new GameEngine();
        ge.StartGame(uids, conventions);
        gameList.put(gid, ge);
    }

    /**
    Завершение указанной игры (без уничтожения объекта игры)
    @param gid Идентификатор игры для завершения
     */
    public void FinishGame(int gid) {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            return;
        }
        ge.FinishGame();
    }

    /**
    Удаление объекта указанной игры
    @param gid Идентификатор удаляемой игры
     */
    public void KillGame(int gid) {
        gameList.remove(gid);
    }

    /**
    Заказ контракта во время торговли
    @param uid Игрок - заказчик
    @param gid Идентификатор игры
    @param tradeRequest Строка заказа контракта
    @throws GameControllerException Не соответствие правилам игры
     */
    public void UserTrade(int uid, int gid, String tradeRequest) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Ошибка в заказе. нет игры с таким gid");
        }
        ge.UserTrade(uid, tradeRequest);
    }

    /**
    Заказ контракта во время торговли
    @param uid Игрок выполняющий ход
    @param gid Идентификатор игры
    @param moveRequest Строка описывающая ход
    @throws GameControllerException Не соответствие правилам игры
     */
    public void UserMove(int uid, int gid, String moveRequest) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Ошибка при торговле. нет игры с таким gid");
        }
        ge.UserMove(uid, moveRequest);
    }

    /**
    Игрок готов к следующей раздаче
    @param uid Идентификатор игрока
    @param gid Идентификатор игры
     */
    public void UserReady(int uid, int gid) {
        GameEngine ge = gameList.get(gid);
        if (ge != null) {
            ge.UserReady(uid);
        }
    }

    /**
    Отмена готовности к следующей раздаче
    @param uid Идентификатор игрока
    @param gid Идентификатор игры
    @throws GameControllerException Не получилось отменить готовность
     */
    public void UserUnready(int uid, int gid) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Ошибка при отказе от готовности. нет игры с таким gid");
        }
        ge.UserUnready(uid);
    }

    /**
    Пуля указанного игрока
    @param uid Идентификатор игрока
    @param gid Идентификатор игры
    @param fullStat Полная запись в поле, или только последнее значение
    @return Запись пули
    @throws GameControllerException Ошибка при получении данных
     */
    public String getUserPool(int uid, int gid, boolean fullStat) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ArrayToString(ge.getUserPool(uid), fullStat);
    }

    /**
    @see GamesManager#getUserPool(int, int, boolean)
     */
    public String getUserPool(int uid, int gid) throws GameControllerException {
        return getUserPool(uid, gid, true);
    }

    /**
    Гора указанного игрока
    @param uid Идентификатор игрока
    @param gid Идентификатор игры
    @param fullStat Полная запись в поле, или только последнее значение
    @return Запись горы
    @throws GameControllerException Ошибка при получении данных
     */
    public String getUserGora(int uid, int gid, boolean fullStat) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ArrayToString(ge.getUserGora(uid), fullStat);
    }

    /**
    @see GamesManager#getUserGora(int, int, boolean)
     */
    public String getUserGora(int uid, int gid) throws GameControllerException {
        return getUserGora(uid, gid, true);
    }

    /**
    Возвращает висты одного игрока на другого
    @param uid1 Владелец вистов
    @param uid2 На кого написаны висты
    @param gid Идентификатор игры
    @param fullStat Полная запись в поле, или только последнее значение
    @return Запись вистов
    @throws GameControllerException Ошибка при получении данных
     */
    public String getUsersWhists(int uid1, int uid2, int gid, boolean fullStat) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ArrayToString(ge.getUsersWhists(uid1, uid2), fullStat);
    }

    /**
    @see GamesManager#getUsersWhists(int, int, int, boolean)
     */
    public String getUsersWhists(int uid1, int uid2, int gid) throws GameControllerException {
        return getUsersWhists(uid1, uid2, gid, true);
    }

    /**
     * Получение конвенций игры
     * @param gid Идентификатор игры
     * @return конвенции игры
     * @throws GameControllerException Ошибка при получении данных
     */
    public GameConventions getConventions(int gid) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ge.getConventions();
    }

    /**
     * Расчет очков для указанного игрока
     * @param uid Идентификатор игрока
     * @param gid Идентификатор игры
     * @return Расчет очков
     * @throws GameControllerException Ошибка при получении данных
     */
    public String getUserScore(int uid, int gid) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return String.valueOf(ge.getUserScore(uid));
    }

    /**
     * Состояние указанной игры
     * @param gid Идентификатор игры
     * @return состояние игры
     * @throws GameControllerException Ошибка получения состояния игры
     */
    public PrefGameState getGameState(int gid) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ge.getGameState();
    }

    /**
     * Список карт на руках у указанного игрока
     * @param uid Идентификатор игрока
     * @param gid Идентификатор игры
     * @return список карт на руках у указанного игрока
     * @throws GameControllerException Ошибка получения списка карт
     */
    public ArrayList<GameCard> getUserCards(int uid, int gid) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ge.getUserCards(uid);
    }

    /**
     * Список карт на столле
     * @param gid Идентификатор игры
     * @return Список карт в массиве (положение на столе: 0-юг, 1-восток, 2-запад, 3-север)
     * @throws GameControllerException Ошибка получения списка карт
     */
    public GameCard[] getCardsOnDesk(int gid) throws GameControllerException {
        GameEngine ge = gameList.get(gid);
        if (ge == null) {
            throw new GameControllerException("Нет игры с таким gid");
        }
        
        return ge.getCardsOnDesk();
    }

    /**
     * Список активных игр
     * @return 
     */
    public ArrayList<Integer> getGamelist() {
        return (ArrayList<Integer>) gameList.keySet();
    }
    
    private String ArrayToString (ArrayList<Integer> inData, boolean fullOut) {
        StringBuilder buf = new StringBuilder();
        
        if (fullOut) {
            for (Integer iValue : inData) {
                if (inData.indexOf(iValue) != 0) {
                    buf.append(", ");
                }
                buf.append(iValue);
            }            
        } else {
            buf.append(inData.get(inData.size() - 1));
        }
        
        return buf.toString();
    }
    
    private Map<Integer, GameEngine> gameList;
}
